#include <stdlib.h>

#include "tm/tmapi.h"

void mainX (int argc, const char** const argv, const char **envp) {
    
    uint size = 64*1024*1024;
    uint size_padded = size*2;
    Sim_Print1("size=%x\n", size);

    char* mem1_start;
    char* mem2_start;
    char* mem3_start;
    char* mem4_start;
    char* mem1_end;
    char* mem2_end;
    char* mem3_end;
    char* mem4_end;
    char* mem1_start_alligned;
    char* mem2_start_alligned;
    char* mem3_start_alligned;
    char* mem4_start_alligned;
    char* mem1_end_alligned;
    char* mem2_end_alligned;
    char* mem3_end_alligned;
    char* mem4_end_alligned;
    TM_BeginClosed(); {
        mem1_start = (char*)malloc(size_padded);
        mem2_start = (char*)malloc(size_padded);
        mem3_start = (char*)malloc(size_padded);
        mem4_start = (char*)malloc(size_padded);

        assert(mem1_start != NULL);
        assert(mem2_start != NULL);
        assert(mem3_start != NULL);
        assert(mem4_start != NULL);

        mem1_end = mem1_start+size_padded;
        mem2_end = mem2_start+size_padded;
        mem3_end = mem3_start+size_padded;
        mem4_end = mem4_start+size_padded;

        assert(mem1_start < mem1_end);
        assert(mem2_start < mem2_end);
        assert(mem3_start < mem3_end);
        assert(mem4_start < mem4_end);

        mem1_start_alligned = (char *)(((long int) mem1_start+size >> 6)<< 6);
        mem2_start_alligned = (char *)(((long int) mem2_start+size >> 6)<< 6);
        mem3_start_alligned = (char *)(((long int) mem3_start+size >> 6)<< 6);
        mem4_start_alligned = (char *)(((long int) mem4_start+size >> 6)<< 6);

        assert(mem1_start <= mem1_start_alligned);
        assert(mem2_start <= mem2_start_alligned);
        assert(mem3_start <= mem3_start_alligned);
        assert(mem4_start <= mem4_start_alligned);

        mem1_end_alligned = mem1_start_alligned+size;
        mem2_end_alligned = mem2_start_alligned+size;
        mem3_end_alligned = mem3_start_alligned+size;
        mem4_end_alligned = mem4_start_alligned+size;

        assert(mem1_end_alligned <= mem1_end);
        assert(mem2_end_alligned <= mem2_end);
        assert(mem3_end_alligned <= mem3_end);
        assert(mem4_end_alligned <= mem4_end);

        Sim_Print4("%x-%x %x-%x\n", (long int)mem1_start, (long int)mem1_end, (long int)mem1_start_alligned, (long int)mem1_end_alligned);
        Sim_Print4("%x-%x %x-%x\n", (long int)mem2_start, (long int)mem2_end, (long int)mem2_start_alligned, (long int)mem2_end_alligned);
        Sim_Print4("%x-%x %x-%x\n", (long int)mem3_start, (long int)mem3_end, (long int)mem3_start_alligned, (long int)mem3_end_alligned);
        Sim_Print4("%x-%x %x-%x\n", (long int)mem4_start, (long int)mem4_end, (long int)mem4_start_alligned, (long int)mem4_end_alligned);
    }
    TM_EndClosed();

#if 1
    {
        //testing 4 way associativity
        for (int j = 0; j < 1; j++)  {
            TM_BeginClosed(); {
                //testing capacity overflows
                for (int i = 0; i < 256*64; i++) {
                    mem1_start_alligned[i] = 's';
                } 
            }
            TM_EndClosed();
        }
    }
#endif

    TM_BeginClosed(); {
        //lets make stride even bigger now
        Sim_Print0("1\n");
        for (int i = 0 ; i < 2*(1+4*512) ; i++ ) {
            uint index = i*32*256;
            assert(index < size);
            mem1_start_alligned[index] = 's';
        }
        Sim_Print0("2\n");
        for (int i =0 ; i < 2*(1+4*512) ; i++ ) {
            uint index = i*32*256;
            assert(index < size);
            mem2_start_alligned[index] = 's';
        }
        Sim_Print0("3\n");
        for (int i =0 ; i < 2*(1+4*512) ; i++ ) {
            uint index = i*32*256;
            assert(index < size);
            mem3_start_alligned[index] = 's';
        }
        Sim_Print0("4\n");
        for (int i =0 ; i < 2*(1+4*512) ; i++ ) {
            uint index = i*32*256;
            assert(index < size);
            mem4_start_alligned[index] = 's';
        }
        Sim_Print0("Done\n");
    }
    TM_EndClosed();

    free(mem1_start);
    free(mem2_start);
    free(mem3_start);
    free(mem4_start);
}
